package br.org.isvi.interpretador.portugol.operations;

import br.org.isvi.interpretador.portugol.InterpreterResolver;
import br.org.isvi.interpretador.portugol.OperationResolver;
import br.org.isvi.interpretador.portugol.exception.SemanticErrorException;
import br.org.isvi.interpretador.portugol.types.IntegerSymbol;
import br.org.isvi.interpretador.portugol.types.Kind;
import br.org.isvi.interpretador.portugol.types.RealSymbol;
import br.org.isvi.interpretador.portugol.types.Symbol;

/**
 * Espera dois termos para somar
 * 
 * @author abraaoisvioliveirasouzadocarmo
 * 
 */
public class MinusResolver implements OperationResolver {

	private double resultado = 0;
	private Kind kindResult = Kind.INTEIRO;

	public Symbol execute() {
		Symbol obj1, obj2 = null;
		Symbol ret = null;

		if (InterpreterResolver.instance.stackSize() < 2) {
			obj1 = InterpreterResolver.instance.popStack();
			
			if(!obj1.compatible(new IntegerSymbol(0))) {
				throw new SemanticErrorException("O Tipo " + UtilsValidator.getRealVariableValue(obj1).getKind() + " não é compatível com esta operação!");
			}
			
			kindResult = UtilsValidator.getRealVariableValue(obj1).getKind();
			
			if(kindResult == Kind.INTEIRO) {
				int i = -((Integer)UtilsValidator.getRealVariableValue(obj1).getValue());
				
				ret = new IntegerSymbol(i);
			} else {
				double i = -((Double)UtilsValidator.getRealVariableValue(obj1).getValue());
				
				ret = new RealSymbol(i);
			}
			
		} else {

			obj1 = InterpreterResolver.instance.popStack();
			obj2 = InterpreterResolver.instance.popStack();

			UtilsValidator.verifyKind(obj1, obj2);

			execute(obj1, obj2);//poderia tbm negativar o elemento 2 aki e somar com o primeiro

			switch (kindResult) {
			case REAL:
				ret = new RealSymbol(resultado);
				break;
			case INTEIRO:
				ret = new IntegerSymbol((int) resultado);
				break;
			}

		}

		return ret;
	}

	private void execute(Symbol obj, Symbol obj2) {
		obj = UtilsValidator.getRealVariableValue(obj);
		obj2 = UtilsValidator.getRealVariableValue(obj2);
		
		Kind k1 = obj.getKind();
		Kind k2 = obj2.getKind();
		
		if(k1 == Kind.REAL || k2 == Kind.REAL) {
			kindResult = Kind.REAL;
		} else {
			kindResult = Kind.INTEIRO;	
		}
		
		double v2 = ((Number)obj2.getValue()).doubleValue();
		double v1 = ((Number)obj.getValue()).doubleValue();
		
		resultado = v2-v1;
	}
}
